﻿// Type: VSFile.SolutionFile
// Assembly: VSFile, Version=1.2.1.0, Culture=neutral, PublicKeyToken=null
// Assembly location: C:\Downloads\VSFile.dll

using System;
using System.Collections.Generic;
using System.IO;
using System.Text.RegularExpressions;

namespace ReadSolutionContents
{
    /// <summary>
    /// Represents a Visual Studio solution file.
    /// 
    /// </summary>
    public class SolutionFile : VisualStudioFile
    {
        /// <summary>
        /// File extension of solution file.
        /// 
        /// </summary>
        public const string SolutionFileExtension = ".sln";
        /// <summary>
        /// Visual Basic project files referenced in this solution file.
        /// 
        /// </summary>
        private List<BasicProjectFile> m_basicProjectFiles;
        /// <summary>
        /// Visual C# project files referenced in this solution file.
        /// 
        /// </summary>
        private List<CSharpProjectFile> m_cSharpProjectFiles;
        /// <summary>
        /// Visual F# project files referenced in this solution file.
        /// 
        /// </summary>
        private List<FSharpProjectFile> m_fSharpProjectFiles;
        /// <summary>
        /// ASP.NET web site directories referenced in this solution file.
        /// 
        /// </summary>
        private List<WebSiteDirectory> m_webSiteDirectories;

        /// <summary>
        /// Get Visual Basic project files referenced in this solution file.
        /// 
        /// </summary>
        /// 
        /// <value>
        /// Enumerable collection of BasicProjectFile objects representing
        ///             Visual Basic project files referenced in this solution file.
        /// 
        /// </value>
        public IEnumerable<BasicProjectFile> BasicProjectFiles
        {
            get
            {
                return (IEnumerable<BasicProjectFile>)this.m_basicProjectFiles;
            }
        }

        /// <summary>
        /// Get Visual C# project files referenced in this solution file.
        /// 
        /// </summary>
        /// 
        /// <value>
        /// Enumerable collection of CSharpProjectFile objects representing
        ///             Visual C# project files referenced in this solution file.
        /// 
        /// </value>
        public IEnumerable<CSharpProjectFile> CSharpProjectFiles
        {
            get
            {
                return (IEnumerable<CSharpProjectFile>)this.m_cSharpProjectFiles;
            }
        }

        /// <summary>
        /// Get Visual F# project files referenced in this solution file.
        /// 
        /// </summary>
        /// 
        /// <value>
        /// Enumerable collection of FSharpProjectFile objects representing
        ///             Visual F# project files referenced in this solution file.
        /// 
        /// </value>
        public IEnumerable<FSharpProjectFile> FSharpProjectFiles
        {
            get
            {
                return (IEnumerable<FSharpProjectFile>)this.m_fSharpProjectFiles;
            }
        }

        /// <summary>
        /// Get ASP.NET web site directories referenced in this solution file.
        /// 
        /// </summary>
        /// 
        /// <value>
        /// Enumerable collection of WebSiteDirectory objects representing
        ///             ASP.NET web site directories referenced in this solution file.
        /// 
        /// </value>
        public IEnumerable<WebSiteDirectory> WebSiteDirectories
        {
            get
            {
                return (IEnumerable<WebSiteDirectory>)this.m_webSiteDirectories;
            }
        }

        /// <summary>
        /// Constructor.
        /// 
        /// </summary>
        /// <param name="filePath">String representing path to solution file.
        ///             </param>
        public SolutionFile(string filePath)
            : base(".sln", filePath)
        {
            this.m_basicProjectFiles = new List<BasicProjectFile>();
            this.m_cSharpProjectFiles = new List<CSharpProjectFile>();
            this.m_fSharpProjectFiles = new List<FSharpProjectFile>();
            this.m_webSiteDirectories = new List<WebSiteDirectory>();
        }

        /// <summary>
        /// Read file.
        /// 
        /// </summary>
        protected override void ReadFile()
        {
            this.ClearFiles();
            using (TextReader textReader = (TextReader)new StreamReader(this.FilePath))
            {
                string inputLine;
                while ((inputLine = textReader.ReadLine()) != null)
                {
                    if (inputLine.StartsWith("Project", StringComparison.Ordinal))
                        this.AddProject(inputLine);
                }
            }
        }

        /// <summary>
        /// Add project given line of input from solution file.
        /// 
        /// </summary>
        /// <param name="inputLine">String representing line of input from solution file.
        ///             </param>
        private void AddProject(string inputLine)
        {
            Match match = System.Text.RegularExpressions.Regex.Match(inputLine, "^Project\\(\"{(?<TypeGUID>[A-F\\d-]+)}\"\\) = \"(?<Name>.+)\", \"(?<Path>.+)\", \"{(?<UniqueGUID>[A-F\\d-]+)}\"$");
            if (!match.Success)
                return;
            string matchValue1 = SolutionFile.GetMatchValue(match, "Name");
            string matchValue2 = SolutionFile.GetMatchValue(match, "TypeGUID");
            string fullPath = this.GetFullPath(SolutionFile.GetMatchValue(match, "Path"));
            switch (matchValue2)
            {
                case "F184B08F-C81C-45F6-A57F-5ABD9991F28F":
                    this.m_basicProjectFiles.Add(new BasicProjectFile(matchValue1, fullPath));
                    break;
                case "FAE04EC0-301F-11D3-BF4B-00C04F79EFBC":
                    this.m_cSharpProjectFiles.Add(new CSharpProjectFile(matchValue1, fullPath));
                    break;
                case "F2A71F9B-5D33-465A-A702-920D77279786":
                    this.m_fSharpProjectFiles.Add(new FSharpProjectFile(matchValue1, fullPath));
                    break;
                case "E24C65DC-7377-472B-9ABA-BC803B73C61A":
                    this.m_webSiteDirectories.Add(new WebSiteDirectory(matchValue1, fullPath));
                    break;
            }
        }

        /// <summary>
        /// Clear referenced project files.
        /// 
        /// </summary>
        private void ClearFiles()
        {
            this.m_basicProjectFiles.Clear();
            this.m_cSharpProjectFiles.Clear();
            this.m_fSharpProjectFiles.Clear();
            this.m_webSiteDirectories.Clear();
        }

        /// <summary>
        /// Get match value at given group name.
        /// 
        /// </summary>
        /// <param name="match">Match representing regular expression match results.
        ///             </param><param name="groupName">String representing name of group to match in given match results.
        ///             </param>
        /// <returns>
        /// String representing match value at given group name.
        /// 
        /// </returns>
        private static string GetMatchValue(Match match, string groupName)
        {
            return match.Groups[groupName].Value;
        }

        /// <summary>
        /// Project tag contained in solution file.
        /// 
        /// </summary>
        private static class ProjectTag
        {
            /// <summary>
            /// Beginning of project tag.
            /// 
            /// </summary>
            public const string Begin = "Project";

            /// <summary>
            /// Regular expression used to obtain data in project tag.
            /// 
            /// </summary>
            public static class Regex
            {
                /// <summary>
                /// Group used to match project name.
                /// 
                /// </summary>
                public const string NameGroup = "Name";
                /// <summary>
                /// Group used to match project path.
                /// 
                /// </summary>
                public const string PathGroup = "Path";
                /// <summary>
                /// Pattern used to match project GUIDs, name and path.
                /// 
                /// </summary>
                public const string Pattern = "^Project\\(\"{(?<TypeGUID>[A-F\\d-]+)}\"\\) = \"(?<Name>.+)\", \"(?<Path>.+)\", \"{(?<UniqueGUID>[A-F\\d-]+)}\"$";
                /// <summary>
                /// Group used to match project type GUID.
                /// 
                /// </summary>
                public const string TypeGuidGroup = "TypeGUID";
                /// <summary>
                /// Group used to match project unique GUID.
                /// 
                /// </summary>
                public const string UniqueGuidGroup = "UniqueGUID";
                /// <summary>
                /// Pattern used to match project name.
                /// 
                /// </summary>
                private const string Name = "\"(?<Name>.+)\"";
                /// <summary>
                /// Pattern used to match project path.
                /// 
                /// </summary>
                private const string Path = "\"(?<Path>.+)\"";

                /// <summary>
                /// GUID patterns.
                /// 
                /// </summary>
                private static class Guid
                {
                    /// <summary>
                    /// Pattern used to match project type GUID.
                    /// 
                    /// </summary>
                    public const string TypeGuid = "\"{(?<TypeGUID>[A-F\\d-]+)}\"";
                    /// <summary>
                    /// Pattern used to match project unique GUID.
                    /// 
                    /// </summary>
                    public const string UniqueGuid = "\"{(?<UniqueGUID>[A-F\\d-]+)}\"";
                    /// <summary>
                    /// Beginning of GUID pattern.
                    /// 
                    /// </summary>
                    private const string Begin = "\"{(?<";
                    /// <summary>
                    /// End of GUID pattern.
                    /// 
                    /// </summary>
                    private const string End = ">[A-F\\d-]+)}\"";
                }
            }
        }

        /// <summary>
        /// GUIDs used to identify types of projects.
        /// 
        /// </summary>
        private static class ProjectTypeGuid
        {
            /// <summary>
            /// Visual Basic project type.
            /// 
            /// </summary>
            public const string Basic = "F184B08F-C81C-45F6-A57F-5ABD9991F28F";
            /// <summary>
            /// Visual C# project type.
            /// 
            /// </summary>
            public const string CSharp = "FAE04EC0-301F-11D3-BF4B-00C04F79EFBC";
            /// <summary>
            /// Visual F# project type.
            /// 
            /// </summary>
            public const string FSharp = "F2A71F9B-5D33-465A-A702-920D77279786";
            /// <summary>
            /// ASP.NET web site project type.
            /// 
            /// </summary>
            public const string WebSite = "E24C65DC-7377-472B-9ABA-BC803B73C61A";
        }
    }
}
